# -*- coding: utf-8 -*-
"""
Puukusoft module: data_box

Purpose
=======
 Provides a means of reading data from a network socket and arranging it into a
 series of discrete lines, simplifying access.
 
Legal
=====
 All code, unless otherwise indicated, is original, and subject to the
 terms of the GPLv2, which is provided in COPYING.
 
 (C) Neil Tallim, 2008
"""
class DataBox(object):
	"""
	A container for data read from a network socket.
	"""
	_buffer = None #: A string of incomplete data read from the network socket.
	_lines = None #: A list of lines successfully read from the network socket.
	
	def __init__(self):
		"""
		Initialises the list of read lines.
		"""
		self._lines = []
		
	def feedData(self, data):
		"""
		Accepts arbitrary data and splits it based on newline characters.
		
		@type data: basestring
		@param data: The data to be processed.
		"""
		if data:
			if self._buffer: #Prepend the fragment, if any.
				data = self._buffer + data
				self._buffer = None
				
			if not data.endswith('\n'): #The received data is incomplete.
				index = data.rfind('\n') #The position at which the last complete line ends.
				if index == -1: #There is no complete data, so buffer everything.
					self._buffer = data
					return
				else: #Stick the fragment in the buffer and parse what's complete.
					self._buffer = data[index + 1:]
					data = data[:index]
					
		for line in data.split('\n'):
			if line: #Ignore empty lines.
				self._lines.append(line)
				
	def getLine(self):
		"""
		Returns the first line from the list of lines successfully parsed.
		
		@rtype: basestr|None
		@return: The first line in the queue, or None if the queue is empty.
		"""
		if self._lines:
			return self._lines.pop(0)
		return None
		
	def getLines(self):
		"""
		Returns all lines successfully parsed.
		
		@rtype: list
		@return: All lines successfully parsed.
		"""
		if self._lines:
			lines = self._lines
			self._lines = []
			return lines
		else:
			return []
			
	def hasLines(self):
		"""
		Indicates whether any lines have been parsed.
		
		@rtype: bool
		@return: True if any lines have been parsed.
		"""
		return len(self._lines) > 0
		